package cn.zyjblogs.sms.provider;

import cn.zyjblogs.sms.common.SmsRequest;
import cn.zyjblogs.sms.common.SmsResponse;
import cn.zyjblogs.sms.task.constant.SendStatus;
import cn.zyjblogs.sms.task.constant.TaskStatus;
import cn.zyjblogs.sms.task.dto.TaskResultDTO;
import cn.zyjblogs.sms.task.mapper.SmsTaskMapper;
import cn.zyjblogs.sms.task.po.SmsSendStatusPO;
import cn.zyjblogs.sms.task.po.SmsTaskPO;
import cn.zyjblogs.sms.task.po.SmsTemplatePO;
import cn.zyjblogs.sms.task.service.SmsSendStatusService;
import cn.zyjblogs.sms.task.service.SmsTemplateService;
import cn.zyjblogs.sms.task.service.impl.SmsTaskServiceImpl;
import cn.zyjblogs.starter.common.entity.context.BaseContext;
import cn.zyjblogs.starter.common.utils.collections.CollectionUtils;
import cn.zyjblogs.starter.common.utils.string.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 消息发送处理器
 *
 * @author zhuyijun
 */
@Component
@RequiredArgsConstructor
public class SmsSendHandler {
    private final SmsTemplateService smsTemplateService;
    private final SmsSendStatusService smsSendStatusService;
    private final SmsTaskMapper smsTaskMapper;
    private final SmsGranter smsGranter;
    private final TransactionTemplate transactionTemplate;
    private static final Logger log = LoggerFactory.getLogger(SmsTaskServiceImpl.class);

    /**
     * 短信发送任务进行发送
     *
     * @param taskId
     * @return void
     * @author zhuyijun
     * @date 2023/4/11 18:14
     */
    public void send(String taskId) {
        SmsTaskPO data = smsTaskMapper.selectById(taskId);
        if (data == null) {
            return;
        }
        SmsTemplatePO template = smsTemplateService.getById(data.getTemplateId());
        if (template == null) {
            return;
        }
        this.send(data, template);
    }

    /**
     * 短信发送任务进行发送
     *
     * @param data
     * @param template
     * @return void
     * @author zhuyijun
     * @date 2023/4/11 18:14
     */
    @Async(value = "asyncServiceExecutor")
    public void send(SmsTaskPO data, SmsTemplatePO template) {
        if (data == null || template == null) {
            return;
        }
        LambdaQueryWrapper<SmsSendStatusPO> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(SmsSendStatusPO::getTaskId, data.getId())
                .eq(SmsSendStatusPO::getSubmitStatus, SendStatus.WAITING);
        List<SmsSendStatusPO> list = smsSendStatusService.list(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            data.setStatus(TaskStatus.SUCCESS);
            smsTaskMapper.updateById(data);
            return;
        }
        Map<String, String> telsMap = list.stream().filter(smsSendStatus -> !StringUtils.isEmpty(smsSendStatus.getTelNum())).collect(Collectors.toMap(SmsSendStatusPO::getTelNum, SmsSendStatusPO::getId, (k1, k2) -> k1));
        List<SmsSendStatusPO> sendStatusList = new LinkedList<>();
        try {
            TaskResultDTO taskResultDTO = smsGranter.sendSms(template.getProviderType(), SmsRequest.builder()
                    .smsTaskPO(data)
                    .smsTemplate(template).telNums(new LinkedList<>(telsMap.keySet()))
                    .build());
            data.setStatus(taskResultDTO.getStatus());
            sendStatusList.addAll(handleSendStatusData(taskResultDTO, data, telsMap));
        } catch (Exception e) {
            log.error("短信发送任务发送失败", e);
            data.setStatus(TaskStatus.FAIL);
        }
        transactionTemplate.execute(status -> {
            if (!CollectionUtils.isEmpty(sendStatusList)) {
                smsSendStatusService.updateBatchById(sendStatusList, 1000);
            }
            smsTaskMapper.updateById(data);
            return true;
        });
    }


    /**
     * 处理短信发送状态
     *
     * @param taskResultDTO 任务结果
     * @param data          短信任务
     */
    public List<SmsSendStatusPO> handleSendStatusData(TaskResultDTO taskResultDTO, SmsTaskPO data, Map<String, String> telsMap) {
        if (taskResultDTO == null) {
            return Collections.emptyList();
        }
        List<SmsResponse> list = taskResultDTO.getResponses();
        if (CollectionUtils.isEmpty(list)) {
            return new LinkedList<>();
        }
        List<SmsSendStatusPO> sendStatusList = new LinkedList<>();
        String tenantId = BaseContext.getTenantId();
        final LocalDateTime now = LocalDateTime.now();
        final String userId = BaseContext.getUserId();
        list.forEach(smsResponse -> {
            if (telsMap.containsKey(smsResponse.getPhoneNumber())) {
                sendStatusList.add(SmsSendStatusPO.builder()
                        .id(telsMap.get(smsResponse.getPhoneNumber()))
                        .taskId(data.getId())
                        .bizId(smsResponse.getBizId())
                        .code(smsResponse.getCode())
                        .message(smsResponse.getMessage())
                        .telNum(smsResponse.getPhoneNumber())
                        .ext(smsResponse.getExt())
                        .sendStatus(smsResponse.getSendStatus())
                        .submitStatus(SendStatus.SUCCESS)
                        .fee(smsResponse.getFee())
                        .createUserId(userId)
                        .createTime(now)
                        .editUserId(userId)
                        .editTime(now)
                        .tenantId(tenantId)
                        .build());
            }
        });
        return sendStatusList;
    }

}
